Skip to content

ZCU-PUB/Partial word match API#1289

Open
Paurikova2 wants to merge 1 commit intocustomer/zcu-pubfrom
zcu-pub/partial-word-match-browsing-using-api
Open

ZCU-PUB/Partial word match API#1289
Paurikova2 wants to merge 1 commit intocustomer/zcu-pubfrom
zcu-pub/partial-word-match-browsing-using-api

Conversation

@Paurikova2
Copy link
Collaborator

Problem description

Analysis

(Write here, if there is needed describe some specific problem. Erase it, when it is not needed.)

Problems

(Write here, if some unexpected problems occur during solving issues. Erase it, when it is not needed.)

Manual Testing (if applicable)

Copilot review

  • Requested review from Copilot

@Paurikova2 Paurikova2 requested a review from Copilot March 19, 2026 12:44
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a startsWith search operator and adjusts Discovery/Solr indexing and submission-authorized collection search to support case-insensitive prefix matching (primarily on titles). It also refactors several REST components to rely on Spring DI for SubmissionConfigService to avoid early factory/service initialization.

Changes:

  • Add startsWith operator support in REST/search operator allowlist and Solr filter query generation.
  • Index container titles into *_sort fields (and add Discovery config for a dc.title-backed filter) to enable prefix matching on communities/collections.
  • Update integration tests and refactor multiple REST services/repositories/converters to use Spring injection for submission config services.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
dspace/config/spring/api/discovery.xml Adds a new Discovery search filter bean targeting dc.title and enables it in the filter list.
dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java Updates/extends IT assertions around prefix matching behavior in submit-authorized collection search.
dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/SubmissionService.java Switches SubmissionConfigService initialization to Spring injection (constructor no longer uses factory).
dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java Migrates to constructor injection for SubmissionConfigService.
dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemRestRepository.java Migrates to constructor injection for SubmissionConfigService.
dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionPanelRestRepository.java Migrates to constructor injection for SubmissionConfigService.
dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/SubmissionDefinitionRestRepository.java Migrates to constructor injection for SubmissionConfigService.
dspace-server-webapp/src/main/java/org/dspace/app/rest/model/query/RestSearchOperator.java Adds startsWith to the allowed operator strings.
dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/WorkspaceItemConverter.java Removes exception-throwing constructor to align with DI changes.
dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/WorkflowItemConverter.java Removes exception-throwing constructor to align with DI changes.
dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java Switches submission config wiring to Spring injection in the base converter.
dspace-api/src/main/java/org/dspace/discovery/indexobject/CommunityIndexFactoryImpl.java Adds title_sort field to community Solr documents for prefix matching.
dspace-api/src/main/java/org/dspace/discovery/indexobject/CollectionIndexFactoryImpl.java Adds title_sort field to collection Solr documents for prefix matching.
dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java Implements startsWith operator mapping to _sort fields and wildcard prefix query generation.
dspace-api/src/main/java/org/dspace/discovery/SearchService.java Updates Javadoc to include startsWith as a supported operator.
dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java Changes submit-authorized collection search to use dc.title_sort:<prefix>* filtering.
dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java Changes config directory initialization to be computed via a getter rather than an eager field initializer.
Comments suppressed due to low confidence (1)

dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java:1308

  • In the startsWith branch, value is mutated (lowercased + escaped) before calling transformDisplayedValue, so DiscoverFilterQuery.displayedValue will end up escaped/lowercased (e.g. testing\ auto) instead of reflecting the user input. Preserve the original raw value for displayedValue (and only use the escaped/lowercased value for the actual filter query).
            if ("startsWith".equals(operator)) {
                // Lowercase and escape the value, then append wildcard for prefix matching.
                // The _sort field uses lowerCaseSort type, so both indexed and query values are lowercased.
                value = ClientUtils.escapeQueryChars(value.toLowerCase());
                filterQuery.append(value).append("*");
            } else if ("equals".equals(operator) || "notequals".equals(operator)) {
                //DO NOT ESCAPE RANGE QUERIES !
                if (!value.matches("\\[.*TO.*\\]")) {
                    value = ClientUtils.escapeQueryChars(value);
                    filterQuery.append(value);
                } else {
                    if (value.matches("\\[\\d{1,4} TO \\d{1,4}\\]")) {
                        int minRange = Integer.parseInt(value.substring(1, value.length() - 1).split(" TO ")[0]);
                        int maxRange = Integer.parseInt(value.substring(1, value.length() - 1).split(" TO ")[1]);
                        value = "[" + String.format("%04d", minRange) + " TO " + String.format("%04d", maxRange) + "]";
                    }
                    filterQuery.append(value);
                }
            } else {
                //DO NOT ESCAPE RANGE QUERIES !
                if (!value.matches("\\[.*TO.*\\]")) {
                    value = ClientUtils.escapeQueryChars(value);
                    filterQuery.append("\"").append(value).append("\"");
                } else {
                    filterQuery.append(value);
                }
            }

            result.setDisplayedValue(transformDisplayedValue(context, field, value));
        }

Comment on lines 103 to 108
private org.dspace.app.rest.utils.Utils utils;
@Autowired
private SubmissionConfigService submissionConfigService;

public SubmissionService() throws SubmissionConfigReaderException {
submissionConfigService = SubmissionServiceFactory.getInstance().getSubmissionConfigService();
public SubmissionService() {
}
if ("startsWith".equals(operator)) {
// Lowercase and escape the value, then append wildcard for prefix matching.
// The _sort field uses lowerCaseSort type, so both indexed and query values are lowercased.
value = ClientUtils.escapeQueryChars(value.toLowerCase());
Comment on lines +788 to +791
* Verify that {@code findSubmitAuthorized} implements word-level prefix matching:
* <ul>
* <li>"te" must find collections whose title contains a word starting with "te".</li>
* <li>"es" must NOT find "Test collection" because no word starts with "es".</li>
Comment on lines +105 to +107
// Also index as "title_sort" so the standard searchFilterTitle-based
// discovery filter (f.title + startsWith) works for communities.
doc.addField("title_sort", title);
Comment on lines +131 to +133
// Also index as "title_sort" so the standard searchFilterTitle-based
// discovery filter (f.title + startsWith) works for collections.
doc.addField("title_sort", title);
Comment on lines +119 to 122
@Autowired
public WorkflowItemRestRepository(SubmissionConfigService submissionConfigService) {
this.submissionConfigService = submissionConfigService;
}
Comment on lines +1027 to +1029
// title that starts with "te" (case-insensitive).
String lowerQ = ClientUtils.escapeQueryChars(q.trim().toLowerCase());
discoverQuery.addFilterQueries("dc.title_sort:" + lowerQ + "*");
Comment on lines 59 to +64
@Autowired
SubmissionService submissionService;
@Autowired
protected SubmissionConfigService submissionConfigService;

public AInprogressItemConverter() throws SubmissionConfigReaderException {
submissionConfigService = SubmissionServiceFactory.getInstance().getSubmissionConfigService();
public AInprogressItemConverter() {
Comment on lines +42 to 45
@Autowired
public SubmissionDefinitionRestRepository(SubmissionConfigService submissionConfigService) {
this.submissionConfigService = submissionConfigService;
}
Comment on lines +149 to +151
@Autowired
public WorkspaceItemRestRepository(SubmissionConfigService submissionConfigService) {
this.submissionConfigService = submissionConfigService;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants